haxefandomcom-20200215-history
FFI Tutorial (Neko)
Introduction This tutorial demonstrates how to call C code from a neko application. We will create a library with two simple C functions. One returns the sum of two numbers. The other appends two string''s together. Then we will call each function from Haxe code. The C Code #include #include #include value sum(value a, value b) { if( !val_is_int(a) || !val_is_int(b) ) return val_null; return alloc_int(val_int(a) + val_int(b)); } value append(value a, value b) { value ret; int lena, lenb; char* str; if( !val_is_string(a) || !val_is_string(b) ) return val_null; lena = val_strlen(a); lenb = val_strlen(b); str = (char*)malloc(lena + lenb + 1); memcpy(str, val_string(a), lena); memcpy(str + lena, val_string(b), lenb); str+ lenb = 0; ret = alloc_string(str); free(str); return ret; } DEFINE_PRIM(sum,2); // function sum with 2 arguments DEFINE_PRIM(append,2); // function append with 2 arguments All functions that will be called from neko must include neko.h. Notice that the parameters and return values are of type ''value. The value type is used to wrap all data passed in and out of C functions. In sum, we expect both input parameters to be int's. If they are not, we return null. We use the neko function val_is_int to check that they are indeed int''s. ''append does a similar check but for string''s using ''val_is_string. The val_int function returns the int stored in a value type. The alloc_int function creates an int to be returned. val_string and alloc_string are analogous functions for string''s. ''val_strlen obviously returns the length of a string value. append could have been written more easily using a neko buffer, but I wanted the example to contain some regular C code. The DEFINE_PRIM macro declares the function to be importable by neko. The first parameter is the function; the second parameter is the number of parameters it takes. Functions that take more than five arguments are handled differently. More info on writing C functions for use with neko can be found with the neko documentation. Compile the Library Compile the code into a shared library. Be sure to add install/neko/include to the include path and link with the neko library (neko.lib for windows or libneko.so for linux), which is in install/neko. Move the binary into the current directory and rename it ffilib.ndll. The Haxe Code import neko.Lib; class FfiTest { public static function main() { trace("sum of 1 and 2 is " + sumFunc(1,2)); trace("\"pet\" appended to \"car\" is \"" + Lib.nekoToHaxe(appendFunc(Lib.haxeToNeko("car"),Lib.haxeToNeko("pet"))) + "\""); } private static var sumFunc = neko.Lib.load("ffilib","sum",2); private static var appendFunc = neko.Lib.load("ffilib","append",2); } We use neko.Lib.load to load the c functions. The first parameter is the name of the .ndll file. The second parameter is the name of the function. The third parameter is the number of input parameters it takes. The function, once loaded, can be called like any other haxe function if it only uses simple types, like sum. append uses strings, which are represented differently in haxe and neko, so we call neko.Lib.haxeToNeko to convert parameters being passed in and neko.Lib.nekoToHaxe to convert the return value. Compile and Run Compile and run with: haxe -neko ffi.n -main FfiTest neko ffi Category:Neko Category:FFI Category:Tutorials Category:C